package cn.backflow.generator;

import cn.backflow.generator.util.GLogger;
import cn.backflow.generator.util.PropertiesHelper;
import cn.backflow.generator.util.PropertyPlaceholderHelper;
import cn.backflow.generator.util.PropertyPlaceholderHelper.PropertyPlaceholderConfigurerResolver;
import cn.backflow.generator.util.typemapping.DatabaseTypeUtils;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;


/**
 * 生成器配置类
 * 用于装载generator.properties,generator.xml文件
 *
 * @author badqiu
 * email badqiu@gmail.com
 */
public class GeneratorProperties {
    private static final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", ":", false);

    private static final String[] PROPERTIES_FILE_NAMES = new String[]{"generator.properties", "generator.xml"};

    private static PropertiesHelper props = new PropertiesHelper(new Properties(), true);

    static {
        reload();
    }

    private GeneratorProperties() {}

    public static void reload() {
        try {
            GLogger.println("Start Load GeneratorPropeties from classpath:" + Arrays.toString(PROPERTIES_FILE_NAMES));
            Properties p = new Properties();
            String[] loadedFiles = PropertiesHelper.loadAllPropertiesFromClassLoader(p, PROPERTIES_FILE_NAMES);
            GLogger.println("GeneratorPropeties Load Success,files:" + Arrays.toString(loadedFiles));

            setSepicalProperties(p, loadedFiles);

            setProperties(p);
            System.out.println(p);
        } catch (IOException e) {
            throw new RuntimeException("Load " + Arrays.toString(PROPERTIES_FILE_NAMES) + " error", e);
        }
    }

    private static void setSepicalProperties(Properties p, String[] loadedFiles) {
        p.put("databaseType", getDatabaseType(p, "databaseType"));
        if (loadedFiles != null && loadedFiles.length > 0) {
            String basedir = p.getProperty("basedir");
            if (basedir != null && basedir.startsWith(".")) {
                p.setProperty("basedir", new File(new File(loadedFiles[0]).getParent(), basedir).getAbsolutePath());
            }
        }
    }

    private static String getDatabaseType(Properties p, String key) {
        String databaseType = DatabaseTypeUtils.getDatabaseTypeByJdbcDriver(p.getProperty("jdbc.driver"));
        return p.getProperty(key, databaseType == null ? "" : databaseType);
    }


    public static Properties getProperties() {
        return props.getProperties();
    }

    public static void setProperties(Properties inputProps) {
        props = new PropertiesHelper(resolveProperties(inputProps), true);
        for (Map.Entry<?, ?> entry : props.entrySet()) {
            GLogger.println("[Property] " + entry.getKey() + "=" + entry.getValue());
        }
    }

    public static String getProperty(String key, String defaultValue) {
        return props.getProperty(key, defaultValue);
    }

    public static String getProperty(String key) {
        return props.getProperty(key);
    }

    public static String getRequiredProperty(String key) {
        return props.getRequiredProperty(key);
    }

    public static int getRequiredInt(String key) {
        return props.getRequiredInt(key);
    }

    public static boolean getRequiredBoolean(String key) {
        return props.getRequiredBoolean(key);
    }

    public static String getNullIfBlank(String key) {
        return props.getNullIfBlank(key);
    }

    public static void setProperty(String key, String value) {
        value = resolveProperty(value, getProperties());
        key = resolveProperty(key, getProperties());
        GLogger.println("[setProperty()] " + key + "=" + value);
        props.setProperty(key, value);
        String dir_value = value.replace('.', '/');
        props.setProperty(key + "_dir", dir_value);
    }

    private static Properties resolveProperties(Properties props) {
        Properties result = new Properties();
        for (Object s : props.keySet()) {
            String sourceKey = s.toString();
            String key = resolveProperty(sourceKey, props);
            String value = resolveProperty(props.getProperty(sourceKey), props);
            result.setProperty(key, value);
        }
        return result;
    }

    private static String resolveProperty(String v, Properties props) {
        PropertyPlaceholderConfigurerResolver propertyPlaceholderConfigurerResolver = new PropertyPlaceholderConfigurerResolver(props);
        return helper.replacePlaceholders(v, propertyPlaceholderConfigurerResolver);
    }

}
